package com.geezdata.cps.base.shiro;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.Filter;

import org.apache.commons.collections.CollectionUtils;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authz.HostFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.redis.core.RedisTemplate;

import com.geezdata.cps.base.config.ApiConfig;
import com.geezdata.cps.base.constant.ShiroConstants;

@Configuration
public class ShiroConfig {
	private static final Logger logger = LoggerFactory.getLogger(ShiroConfig.class);
	
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager, ApiConfig apiConfig) {
        logger.info("注入Shiro的Web过滤器-->shiroFilter", ShiroFilterFactoryBean.class);
        MyShiroFilterFactoryBean shiroFilterFactoryBean = new MyShiroFilterFactoryBean(apiConfig.getAuthorizedHosts());
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //要求登录时的链接(可根据项目的URL进行替换),非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilterFactoryBean.setLoginUrl("/login");
        //登录成功后要跳转的连接,逻辑也可以自定义，例如返回上次请求的页面
        shiroFilterFactoryBean.setSuccessUrl("/index");
        //用户访问未对其授权的资源时,所显示的连接
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
        
        HostFilter host = new DefaultHostFilter(apiConfig.getAuthorizedHosts());
        Map<String, Filter > filters = new HashMap<String, Filter>();
        filters.put("host", host);
        shiroFilterFactoryBean.setFilters(filters);
        
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        filterChainDefinitionMap.put("/logout", "logout");
        filterChainDefinitionMap.put("/login", "ssl, anon");
        if(CollectionUtils.isNotEmpty(apiConfig.getShiroAnonUrl())) {
        	 apiConfig.getShiroAnonUrl().stream().forEach(anonUrl -> filterChainDefinitionMap.put(anonUrl, "anon"));
        }
        
        filterChainDefinitionMap.put("/**", "host, authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return shiroFilterFactoryBean;
    }
    
    @Bean
    public ShiroSession shiroSession(RedisTemplate<Object, Object> redisTemplate) {
        return new ShiroSession(redisTemplate);
    }
    
    @Bean
    public ShiroCacheManager shiroCacheManager(RedisTemplate<Object, Object> redisTemplate) {
    	logger.info("注入Shiro的RedisCacheManager-->redisTemplate: {}", redisTemplate);
        return new ShiroCacheManager(redisTemplate);
    }
    
    @Bean
    public SessionManager sessionManager(ShiroSession shiroSession, ShiroCacheManager shiroCacheManager) {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(shiroSession);
        sessionManager.setCacheManager(shiroCacheManager);
        sessionManager.setGlobalSessionTimeout(ShiroConstants.EXPIRE_TIME * 1000);
        return sessionManager;
    }

    @Bean
    public SecurityManager securityManager(SessionManager sessionManager, ShiroCacheManager shiroCacheManager) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm());
        securityManager.setSessionManager(sessionManager);
        securityManager.setCacheManager(shiroCacheManager);
        return securityManager;
    }
    
    @Bean
    public UserRealm userRealm() {
        UserRealm userRealm = new UserRealm();
        //告诉realm,使用credentialsMatcher加密算法类来验证密文
        userRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        userRealm.setAuthorizationCacheName("userRolesAndPermissions");
        return userRealm;
    }

    @Bean(name="credentialsMatcher")
    public SimpleCredentialsMatcher hashedCredentialsMatcher(){
       return new SimpleCredentialsMatcher();
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
        return new LifecycleBeanPostProcessor();
    }
    
    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }
    
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}
